#!/usr/bin/env ruby

# -------------------------------------------------------------------------- #
# Copyright 2002-2016, OpenNebula Project, OpenNebula Systems                #
#                                                                            #
# Licensed under the Apache License, Version 2.0 (the "License"); you may    #
# not use this file except in compliance with the License. You may obtain    #
# a copy of the License at                                                   #
#                                                                            #
# http://www.apache.org/licenses/LICENSE-2.0                                 #
#                                                                            #
# Unless required by applicable law or agreed to in writing, software        #
# distributed under the License is distributed on an "AS IS" BASIS,          #
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   #
# See the License for the specific language governing permissions and        #
# limitations under the License.                                             #
#--------------------------------------------------------------------------- #

require 'fileutils'
require 'tmpdir'


DEFAULTS={
    :version => "5.2.0",
    :date => Time.now.strftime("%Y-%m-%d"),
    :dependencies => []
}

TEMPLATE=<<EOT
# This file is automatically generated

Gem::Specification.new do |s|
  s.name        = '$(NAME)'
  s.version     = '$(VERSION)'
  s.date        = '$(DATE)'
  s.summary     = "$(SUMMARY)"
  s.description = "$(DESCRIPTION)"
  s.authors     = ["OpenNebula"]
  s.email       = 'contact@opennebula.org'
  s.license     = 'Apache-2.0'
  s.files       = [
$(FILES)
  ]
  s.homepage    = 'http://opennebula.org'
$(EXECUTABLES)
$(DEPENDENCIES)
end

EOT

GEM_DESCRIPTION={
    :oca => {
        :name => 'opennebula',
        :files => [
            ['src/oca/ruby/opennebula.rb', '/lib'],

            # Needed for onevcenter
            ['src/vmm_mad/remotes/vcenter/vcenter_driver.rb', '/lib'],

            # vcenter_driver.rb dependencies
            ['src/mad/ruby/VirtualMachineDriver.rb', '/lib'],
            ['src/mad/ruby/OpenNebulaDriver.rb', '/lib'],
            ['src/mad/ruby/CommandManager.rb', '/lib'],
            ['src/mad/ruby/ActionManager.rb', '/lib'],
            ['src/mad/ruby/DriverExecHelper.rb', '/lib'],

            ['src/oca/ruby/opennebula/*.rb', '/lib/opennebula'],
            ['src/authm_mad/remotes/**/*.rb', '/lib/opennebula'],
            ['src/cloud/common/CloudClient.rb', '/lib/cloud'],
            ['NOTICE', ''],
            ['LICENSE', '']
        ],
        :summary => 'OpenNebula Client API',
        :description => 'Libraries needed to talk to OpenNebula',
        :dependencies => [
            'nokogiri',
            'json',
            'rbvmomi'
        ]
    },

    :cli => {
        :name => 'opennebula-cli',
        :files => [
            ['src/cli/one[a-z]*', '/bin'],
            ['src/cli/*.rb', '/lib'],
            ['src/cli/one_helper/*.rb', '/lib/one_helper'],
            ['NOTICE', ''],
            ['LICENSE', '']
        ],
        :summary => 'OpenNebula Command Line Interface',
        :description => 'Commands used to talk to OpenNebula',
        :dependencies => [
            ['opennebula', "= #{DEFAULTS[:version]}"]
        ]
    }
}

def sane_prefix(prefix)
    return '' if !prefix or prefix.empty?

    p=prefix

    p.slice!(0) if p[0,1]=='/'
    p<<'/' if p[-1,1]!='/'

    p
end

def file_list(description)
    files=Array.new

    description[:files].each do |f, prefix|
        source=Dir.glob(f)

        files+=source.map do |source|
            [source, sane_prefix(prefix)+File.basename(source)]
        end
    end

    files
end

def copy_files(files, source_prefix='', destination_prefix='')
    files.each do |file|
        source=source_prefix+file[0]
        destination=destination_prefix+file[1]

        dir=File.dirname destination

        FileUtils.mkdir_p(dir) if !File.exist?(dir)

        FileUtils.cp(source, destination)
    end
end

def generate_gem_file_list(files)
    files.map do |f|
        "    '#{f.last}'"
    end.join(",\n")
end

def generate_gem_executable_list(files)
    executables=files.
        select {|f| f.last.match(/^bin\//) }.
        map {|f| "'#{File.basename(f.last)}'" }.
        join(", ")

    if !executables.empty?
        "  s.executables=[#{executables}]"
    else
        nil
    end
end

def generate_dependencies(dependencies)
    dependencies.map do |d|
        line="  s.add_runtime_dependency "
        if Array===d
            line<<d.map {|part| "'#{part}'" }.join(", ")
        else
            line<<"'#{d}'"
        end
        line
    end.join("\n")
end

def populate_gem_template(description, files)
    reg=/\$\((\w+)\)/
    TEMPLATE.gsub(reg) do |chunk|
        m=chunk.match(reg)
        var=m[1].downcase.to_sym

        if var==:files
            generate_gem_file_list(files)
        elsif var==:dependencies
            generate_dependencies(
                description[:dependencies]||DEFAULTS[:dependencies])
        elsif var==:executables
            generate_gem_executable_list(files)
        elsif description[var]
            description[var]
        else
            DEFAULTS[var]
        end
    end
end

def generate_gem_file(gem_file, description, files)
    File.open(gem_file, "w") do |f|
        f.write(populate_gem_template(description, files))
    end
end

def generate_gem(description)
    Dir.mktmpdir do |tmp|
        files=file_list(description)
        copy_files(files, '', tmp+"/")

        gem_file=tmp+"/gem.gemspec"
        generate_gem_file(gem_file, description, files)

        pwd=Dir.pwd

        Dir.chdir(tmp) do
            system("gem build gem.gemspec")

            if $?.exitstatus!=0
                puts "Error generating gem"
                exit(-1)
            end

            Dir.glob("*.gem").each do |f|
                FileUtils.cp(f, pwd) 
            end
        end
    end
end

# Go to source code root dir
root=Dir.pwd
root.gsub!(/\/share\/rubygems$/, '')
Dir.chdir(root)


GEM_DESCRIPTION.each {|name, gem| generate_gem(gem) }

